#include "../HelpLibs/RandomGen.h"
#include <iostream>
#include <vector>
#include "../HelpLibs/Observable.h"
#include <armadillo>
using namespace std;
using namespace arma;

struct MultiVariateNormal {
	typedef boost::normal_distribution<> NormalVariable;
	MTGen gen_;
	int n_;
	vec mean_;
	mat rot_;
	RandomVariable<MTGen, NormalVariable> nd_;
	void init(mat cov, vec mean) {
		gen_.seed(0);
		nd_.init(&gen_, NormalVariable::param_type(0, 1));
		rot_ = chol(cov);
		mean_ = mean;
		n_ = mean.size();
	}
	;
	void draw(vec &draw) {
		draw = zeros(n_);
		generate(draw.begin(), draw.end(), [&]() {return nd_.draw();});
		draw = rot_ * draw + mean_;
	}
};

class ObsTest {
	vector<vec> obsData;
	ArrayObservableBin<double, 1> obs_;
	int numOfSamples_;
	MultiVariateNormal rnd_;
public:
	void init(int sampSize, int numOfBins, int binSize) {
		mat cov;
		cov << 0.5 << 0.1 << 0.1 << 0.5;
		cov.reshape(2, 2);
		vec mean;
		mean << 5 << 5;
		numOfSamples_ = numOfBins * binSize;
		rnd_.init(cov, mean);
		ScalarBinObs<double>::InitData initData = { numOfBins, binSize };
		boost::array<int, 1> size = { sampSize };
		obs_.init(size, initData);
	}
	void draw() {
		vec draw;
		for (int n = 0; n < numOfSamples_; n++) {
			rnd_.draw(draw);
			auto iterDraw = draw.begin();
			auto iterObs = obs_.begin();
			for (; iterDraw < draw.end(); iterDraw++, iterObs++)
				*iterObs << *iterDraw;
		}
	}
	void dump() {
		hdf5RW h5_file;
		h5_file.initNew("/u/snirgaz/test.h5");
		obs_.dumpToFile(h5_file, "/samp");
	}
};

int main() {
	ObsTest obsTest;
	int binSize, numOfBins;
	cin >> numOfBins;
	cin >> binSize;
	obsTest.init(2, numOfBins, binSize);
	obsTest.draw();
	obsTest.dump();
}
